package com.spzx.alex008cache20250513.aop;

import com.spzx.alex008cache20250513.annotation.Alex008Cache;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class Alex008CacheAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedissonClient redisson;

    private static final String NULL_VALUE = "NULL";

    @Around("@annotation(alex008Cache)")
    public Object doAround(ProceedingJoinPoint joinPoint, Alex008Cache alex008Cache) throws Throwable {
        String key = buildKey(joinPoint, alex008Cache);

        // 如果是删除缓存操作
        if (alex008Cache.deleteCache()) {
            return handleDeleteCache(joinPoint, key, alex008Cache);
        }

        // 如果是查询操作
        return handleQueryCache(joinPoint, key, alex008Cache);
    }

    // 处理删除缓存的逻辑
    private Object handleDeleteCache(ProceedingJoinPoint joinPoint, String key, Alex008Cache alex008Cache) throws Throwable {
        try {
            // 先执行业务方法
            Object result = joinPoint.proceed();
            
            // 异步删除缓存
            if (alex008Cache.async()) {
                CompletableFuture.runAsync(() -> {
                    redisTemplate.delete(key);
                    log.info("异步删除缓存 key: {}", key);
                });
            } else {
                redisTemplate.delete(key);
                log.info("同步删除缓存 key: {}", key);
            }
            
            return result;
        } catch (Exception e) {
            log.error("删除缓存操作失败", e);
            throw e;
        }
    }

    // 处理查询缓存的逻辑
    private Object handleQueryCache(ProceedingJoinPoint joinPoint, String key, Alex008Cache alex008Cache) throws Throwable {
        try {
            // 查询缓存
            Object cacheValue = redisTemplate.opsForValue().get(key);
            if (cacheValue != null) {
                return NULL_VALUE.equals(cacheValue) ? null : cacheValue;
            }

            // 如果需要加锁
            if (alex008Cache.lock()) {
                return handleCacheWithLock(joinPoint, key, alex008Cache);
            } else {
                return handleCacheWithoutLock(joinPoint, key, alex008Cache);
            }
        } catch (Exception e) {
            log.error("查询缓存操作失败", e);
            return joinPoint.proceed(); // 降级处理
        }
    }

    // 带锁的缓存处理
    private Object handleCacheWithLock(ProceedingJoinPoint joinPoint, String key, Alex008Cache alex008Cache) throws Throwable {
        RLock lock = redisson.getLock("lock:" + key);
        try {
            boolean locked = lock.tryLock(3, 30, TimeUnit.SECONDS);
            if (!locked) {
                throw new RuntimeException("获取锁失败");
            }

            // 双重检查
            Object cacheValue = redisTemplate.opsForValue().get(key);
            if (cacheValue != null) {
                return NULL_VALUE.equals(cacheValue) ? null : cacheValue;
            }

            return getAndCacheValue(joinPoint, alex008Cache, key);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    // 不带锁的缓存处理
    private Object handleCacheWithoutLock(ProceedingJoinPoint joinPoint, String key, Alex008Cache alex008Cache) throws Throwable {
        return getAndCacheValue(joinPoint, alex008Cache, key);
    }

    // 获取并缓存值
    private Object getAndCacheValue(ProceedingJoinPoint joinPoint, Alex008Cache alex008Cache, String key) throws Throwable {
        Object result = joinPoint.proceed();

        // 处理空值
        if (result == null) {
            redisTemplate.opsForValue().set(key, NULL_VALUE, 5, TimeUnit.MINUTES);
            return null;
        }

        // 异步缓存
        if (alex008Cache.async()) {
            CompletableFuture.runAsync(() -> {
                redisTemplate.opsForValue().set(key, result, alex008Cache.expire(), alex008Cache.timeUnit());
                log.info("异步写入缓存 key: {}", key);
            });
        } else {
            redisTemplate.opsForValue().set(key, result, alex008Cache.expire(), alex008Cache.timeUnit());
            log.info("同步写入缓存 key: {}", key);
        }

        return result;
    }

    // buildKey方法保持不变
    private String buildKey(ProceedingJoinPoint joinPoint, Alex008Cache alex008Cache) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = signature.getParameterNames();
        Object[] args = joinPoint.getArgs();

        for (int i = 0; i < paramNames.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }

        return parser.parseExpression(alex008Cache.key()).getValue(context, String.class);
    }
}